/*
 * Copyright 2009 Original Author(s)
 * 
 * This file is part of Kommando
 * 
 * Kommando is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Kommando is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Kommando.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.kommando.core.controlcenter;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.JComponent;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;

import org.kommando.core.util.Assert;

/**
 * {@link TreeModel} implementation for showing {@link PreferencePage}s in a tree.
 * 
 * @author Peter De Bruycker
 */
public class PreferencePageTreeModel implements TreeModel {

    private List<TreeModelListener> listeners = new ArrayList<TreeModelListener>();

    private static final PreferencePage ROOT = new RootPreferencePage();

    private Map<PreferencePage, List<PreferencePage>> pageMap = new HashMap<PreferencePage, List<PreferencePage>>();

    private PreferencePage getPage(List<PreferencePage> pages, String id) {
        if (id == null) {
            return ROOT;
        }

        for (PreferencePage page : pages) {
            if (page.getId().equals(id)) {
                return page;
            }
        }

        // TODO log warning: page for id not found
        return ROOT;
    }

    public void setPages(List<PreferencePage> pages) {
        Assert.argumentNotNull("pages", pages);

        pageMap.clear();
        
        pageMap.put(ROOT, new ArrayList<PreferencePage>());

        for (PreferencePage page : pages) {
            // register the page as a child of its parent page
            addPage(getPage(pages, page.getParentId()), page);

            // register the page as a potential parent
            if (!pageMap.containsKey(page)) {
                pageMap.put(page, new ArrayList<PreferencePage>());
            }
        }

        TreeModelEvent event = new TreeModelEvent(ROOT, new TreePath(ROOT));
        for (TreeModelListener l : listeners) {
            l.treeStructureChanged(event);
        }
    }

    private void addPage(PreferencePage parent, PreferencePage child) {
        if (!pageMap.containsKey(parent)) {
            pageMap.put(parent, new ArrayList<PreferencePage>());
        }

        pageMap.get(parent).add(child);
    }

    @Override
    public void addTreeModelListener(TreeModelListener l) {
        if (!listeners.contains(l)) {
            listeners.add(l);
        }
    }

    @Override
    public void removeTreeModelListener(TreeModelListener l) {
        if (listeners.contains(l)) {
            listeners.remove(l);
        }
    }

    @Override
    public Object getChild(Object parent, int index) {
        return pageMap.get(parent).get(index);
    }

    @Override
    public int getChildCount(Object parent) {
        return pageMap.get(parent).size();
    }

    @Override
    public int getIndexOfChild(Object parent, Object child) {
        return pageMap.get(parent).indexOf(child);
    }

    @Override
    public Object getRoot() {
        return ROOT;
    }

    @Override
    public boolean isLeaf(Object node) {
        return pageMap.get(node).isEmpty();
    }

    @Override
    public void valueForPathChanged(TreePath path, Object value) {
        // not used
    }

    private static class RootPreferencePage implements PreferencePage {

        @Override
        public boolean apply() {
            return true;
        }

        @Override
        public JComponent getComponent() {
            return null;
        }

        @Override
        public String getName() {
            return null;
        }

        @Override
        public String getParentId() {
            return null;
        }

        @Override
        public void restoreDefaults() {
        }

        @Override
        public String getId() {
            return null;
        }

    }

}
